#include <mips/regdef.h>
#include <sys/syscall.h>

		.align          2
		.text
		.globl          main
		.ent            main

main:               
		.frame          $fp, 48, ra
		.set            noreorder
		.cpload         t9
		.set            reorder
		subu            sp, sp, 48
		.cprestore      32
		sw              s0, 44(sp)
		sw              $fp,40(sp)
		sw              ra, 36(sp) 
		move            $fp, sp
	
		# cargar argumentos de consola
		li              a3, 1
		beq             a0, a3, leer        #si a0=1 es porque no hay opcion -l
		li              a3, 3
		bne             a0, a3, readError

		# si llego hasta aca es porque tiene el param -l ###
		# verificamos que sea efectivamente el parametro "l"
		lw              a0, 4(a1)           # cargo la direccion del "-l" en a0
		jal             verificar_parametro
		
		# si v0 = 0 hay un error
		beqz            v0, readError 
 
		lw              a0, 8(a1)           # cargo la direccion del numero en a0
		jal             procesar_digito     # en v1 se guarda el valor "length"
		sw              v1, 24(sp)          # guardamos el valor "length"
		li              s0, 0               # inicializo el iterador de break en 0
		lw              s1, 24(sp)
leer:                      
		# leo 1 byte de stdin
		li              v0, SYS_read        # vo guarda el tipo de syscall
		li              a0, 0               # a0 es el archivo (stdin = 0)
		la              a1, 20(sp)          # a1 es donde se guarda lo leido
		li              a2, 1               # a2 es la cantidad de bytes    
		syscall

		# chequeamos posibles errores
		bnez            a3, final           # if (a3 != 0) return
		li              t0, 1
		bne             v0, t0, final       # if (v0 != 1) return
		
		# preparamos los argumentos y llamamos a bin2hex
		lb              a0, 20(sp)
		jal             bin2hex
		sb              v0, 16(sp)
		sb              v1, 17(sp)

		# escribo 2 bytes a stdout
		li              v0, SYS_write    
		li              a0, 1
		la              a1, 16(sp)
		li              a2, 2
		syscall                             # fprintf(stdout, 13(sp), 2) 
        
		#chequeamos posibles errores
		bnez            a3, final           # if (a3 != 0) return
		li              t0, 2
		bne             v0, t0, final       # if (v0 != 1) return

		#salto de linea
		addu            s0, s0, 1
		bne             s0, s1, noNewLine
		li              s0, 0
		li              v0, SYS_write    
		li              a0, 1
		la              a1, newline
		li              a2, 2
		syscall
        
		#chequeamos posibles errores
		bnez            a3, final           # if (a3 != 0) return
		li              t0, 2
		bne             v0, t0, final       # if (v0 != 1) return
	        
noNewLine:
		# leimos 1 letra, seguimos loopeando
		b               leer

readError:
		li              v0, SYS_exit
		li              a0, 1
		syscall
final:
		move            v0, zero            # return 0
		move            sp, $fp             # restauro sp
		lw              ra, 36(sp)          # restauro ra
		lw              $fp,40(sp)          # restauro $fp
		lw              s0, 44(sp)          # restauro s0
		addu            sp, sp, 48          # restauro sp
		j               ra
		.end      main

#----------------------------------------------------------#

		.ent    verificar_parametro
verificar_parametro:
		.frame          $fp, 16, ra
		.set            noreorder
		.cpload         t9
		.set            reorder
		subu            sp, sp, 16
		.cprestore      8
		sw              $fp, 12(sp)
		move            $fp, sp

		#guardamos los argumentos en el stack frame del caller
		sw              a0, 16(sp)

		#guardamos los datos
		sw              a0, 4(sp)
		lw              t0, 4(sp)              # cargo la direccion del flag en t0
		lb              t1, 1(t0)              # cargo el flag en t1
		li              t2, 108                # valor entero del "l"
		beq             t1, t2, setValorUno    # si es "-l"
		li              v0, 0                  # si no es "l" 
		b               salir
setValorUno:
		li              v0, 1
salir:		
		move            sp, $fp                # restauro sp
		lw              $fp,12(sp)             # restauro $fp
		addu            sp, sp, 16
		j               ra
		.end    verificar_parametro
		
#----------------------------------------------------------#


		.ent     procesar_digito
procesar_digito:
		.frame          $fp, 16, ra
		.set            noreorder
		.cpload         t9
		.set            reorder
		subu            sp, sp, 16
		.cprestore      8
		sw              $fp, 12(sp)
		move            $fp, sp
		
		#guardamos los argumentos en el stack frame del caller
		sw              a0, 16(sp)

		#guardamos los datos
		sw              a0, 4(sp)
		li              v0, 0
		lw              t3, 4(sp)         # en t3 pongo la direccion de valor "lenght" 

procesar_digito_loop:
		# while (!fin)
		# leo un char
		lbu             t1, 0(t3)         # t1 = string[0]
		
		# si no es un digito, fin
		bltu            t1, 48, fin       # if (t1 < 48) fin
		bgtu            t1, 57, fin       # if (t1 > 57) fin
			
		# pasar char a numero
		subu            t1, t1, 48        # t1 = t1 - 48
		
		# v0 = v0 * 10
		li              t2, 10
		mult            v0, t2
		mflo            v0
 
		# agrego el digito
		add             v0, v0, t1        # v0 = v0 + t1
 
		# siguiente digito
		addu            t3, t3, 1               # t3 = t3 + 1
		b               procesar_digito_loop    # end while
		
fin:
		move            v1, v0            # cargo el valor "lenght" en v1
		move            sp, $fp           # restauro sp
		lw              gp, 8(sp)         # restauro gp
		lw              $fp,12(sp)        # restauro $fp
		addu            sp, sp, 16             
		j               ra
		.end    procesar_digito

#----------------------------------------------------------#

		.ent  bin2hex
bin2hex:
		.frame          $fp, 16, ra
		.set            noreorder
		.cpload         t9
		.set            reorder
		subu            sp, sp, 16
		.cprestore      8
		sw              $fp, 12(sp)
		move            $fp, sp
		
		# guardamos los argumentos en el stack del caller
		sb              a0, 16(sp)
		
		# guardamos los argumentos en el stack del calle
		sb              a0, 4(sp)
		
		# empezamos a procesar
		lbu             t0, 4(sp)         #t0=letra
		move            t2, zero          #t2=i
		move            t3, zero          #t3=scale
		move            t4, zero          #t4=value1
		move            t5, zero          #t5=value2
		li              t6, 4             #t6=4
		li              t8, 8             #t8=8 condicion de corte
		li              t9, 10            #t9=10 condicion de salto para interpretar
		addiu           t3, t3, 1         # scale++
deNuevo:
		andi            t7, t0, 1         # mascara
		beqz            t7, sigByte       # si el ultimo bit es =0 salta
		bge             t2, t6, seteaV2   # if(i=>4) salta
		addu            t4, t4, t3        # value1 = value1 + scale
		b               sigByte
seteaV2:
		addu            t5, t5, t3        # value2 = value2 + scale
sigByte:
		addiu           t2, t2, 1            # i++
		beq             t2, t8, imprimir     # if(i==8) imprime
		bne             t2, t6, multip2      # if(i!=4) salta
		li              t3, 1                # scale = 1
		b               desplazar
multip2:
		sll             t3, t3, 1            #scale = scale * 2
desplazar:
		srl             t0, t0, 1            #desplazamiento de la letra
		b               deNuevo
imprimir:
		# formatea a numeros / letras
		bge             t5, t9, letra1       #salta si t5 >= 10 (es letra)
		addiu           t5, t5, 48
		b               finletra1
letra1:
		addiu           t5,t5, 55
finletra1:
		bge             t4, t9, letra2       #salta si t4 >= 10 (es letra)
		addiu           t4, t4, 48
		b               finletra2
letra2:
		addiu           t4, t4, 55
finletra2:
		# guardamos el resultado en v0 y en v1
		move            v0, t5
		move            v1, t4
		
		move            sp, $fp              # restauro sp
		lw              $fp,12(sp)           # restauro $fp
		addu            sp, sp, 16
		j               ra
		.end    bin2hex
		
newline:	.asciiz "\n" 
